define(['esri/layers/GraphicsLayer', "esri/geometry/Point", ], function(Layer, Point) {
    var animationLayer = Layer.createSubclass({
        visible: true,
        _elementVisible: true,
        setData: function(mapView, layer) {
            var me = this;
            var options = layer.layer || {};
            me.data = $.extend(true, [], options.data);
            me._datas = me.data;
            me.options = Object.assign({ size: 10, radius: 1 }, options.options);
            me.options.minScale = options.minScale || 0;
            me.options.maxScale = options.maxScale || 0;
            me.devicePixelRatio = 1;
            me.mapv = options.mapv;
            me.style = options.style;
            me.createCanvas();
            me.init();
            me.startMapEventListeners();
        },
        /*添加监听*/
        startMapEventListeners: function() {
            var me = this;
            let view = this.view;
            this._watchExtent = view.watch("extent", function() {
                if (!me.visible) {
                    return;
                };
                me._refresh();
            });
        },
        createCanvas: function() {
            let canvas = document.createElement('canvas');
            canvas.width = this.view.width;
            canvas.height = this.view.height;
            canvas.setAttribute("id", "heatmap");
            canvas.style.position = "absolute";
            canvas.style.top = 0;
            canvas.style.left = 0;
            if (!this.view) {
                console.log('缺少view!');
            };
            let parent = this.view.canvas.parentElement;
            parent.appendChild(canvas);
            this.canvas = canvas;
            this.context = canvas.getContext('2d');
        },
        init: function() {
            var me = this;
            this.context = this.context || this.canvas.getContext('2d');
            if (this.canvas && this.mapv) {
                var ctx = this.ctx = this.context;

                var DataSet = this.mapv.DataSet;
                var data = this.data;
                var dataSet = new DataSet(data);
                this.dataSet = dataSet;
                this.initDataRange(this.options);
                if (this.options.zIndex) {
                    this.canvasLayer && this.canvasLayer.setZIndex(this.options.zIndex);
                }

                if (this.options.max) {
                    this.intensity.setMax(this.options.max);
                }

                if (this.options.min) {
                    this.intensity.setMin(this.options.min);
                }

                me.initAnimator();
                me._refresh();
            }
        },
        initDataRange: function(options) {
            var self = this;
            var mapv = this.mapv;
            if (!self.options) {
                return;
            }
            self.intensity = new mapv.utilDataRangeIntensity({
                maxSize: self.options.maxSize,
                minSize: self.options.minSize,
                gradient: self.options.gradient,
                max: self.options.max || this.dataSet.getMax('count')
            });
            self.category = new mapv.utilDataRangeCategory(self.options.splitList);
            self.choropleth = new mapv.utilDataRangeChoropleth(self.options.splitList);
            if (self.options.splitList === undefined) {
                self.category.generateByDataSet(this.dataSet, self.options.color);
            }
            if (self.options.splitList === undefined) {
                var min = self.options.min || this.dataSet.getMin('count');
                var max = self.options.max || this.dataSet.getMax('count');
                self.choropleth.generateByMinMax(min, max);
            };
        },
        initAnimator: function() {
            var self = this;
            var animationOptions = self.options.animation;

            if (self.options.draw == 'time' || self.isEnabledTime()) {

                if (!animationOptions.stepsRange) {
                    animationOptions.stepsRange = {
                        start: this.dataSet.getMin('time') || 0,
                        end: this.dataSet.getMax('time') || 0
                    };
                }

                this.steps = { step: animationOptions.stepsRange.start };
                self.animator = new this.mapv.TWEEN.Tween(this.steps).onUpdate(function() {
                    self._canvasUpdate(this.step);
                }).repeat(Infinity);

                this.addAnimatorEvent();

                var duration = animationOptions.duration * 1000 || 5000;

                self.animator.to({ step: animationOptions.stepsRange.end }, duration);
                self.animator.start();
            } else {
                self.animator && self.animator.stop();
            }
        },
        isEnabledTime: function() {
            var animationOptions = this.options.animation;
            var flag = animationOptions && !(animationOptions.enabled === false);
            return flag;
        },
        transferCoordinate: function(coordinate) {
            var view = this.view;
            if (!view) {
                console.log('缺少view!');
                return;
            }
            var point = new Point(coordinate[0], coordinate[1], view.spatialReference);
            var pixel = view.toScreen(point);
            return [pixel.x, pixel.y];
        },
        filterData() {
            var extent = this.view.extent;
            let newData = [];
            for (let i = 0; i < this._datas.length; i++) {
                let obj = this._datas[i];
                let coor = obj.geometry.coordinates;
                let item = { x: coor[0], y: coor[1] };
                if (extent.xmin <= item.x && extent.xmax >= item.x &&
                    extent.ymin <= item.y && extent.ymax >= item.y) {
                    newData.push(obj);
                }
            };
            var DataSet = this.mapv.DataSet;
            var dataSet = new DataSet(newData);
            this.dataSet = dataSet;
            return dataSet;
        },
        clear: function() {
            this.canvas.width = this.view.width;
            this.canvas.height = this.view.height;
            this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
            this.canvasResolutionScale(this.ctx);
            this.mapv.canvasClear(this.ctx);
        },
        _refresh: function() {
            if (this.canvas && this.mapv) {
                this.clear();

                var dataGetOptions = {
                    transferCoordinate: this.transferCoordinate.bind(this)
                };

                this.filterData();
                this.data = this.dataSet.get(dataGetOptions);
                this.processData(this.data);
                this.start();
            };
        },
        start: function() {
            this.stop();
            if (!this.visible) {
                return;
            };
            if (this.view) {
                this.setScale(this.view, this.canvas);
            };
            if (!this._elementVisible) {
                return;
            };

            this.animate();
        },
        setScale: function(view, _element) {
            var scale = view.scale;

            if (this.options && this.options.minScale && this.options.maxScale) {
                if (scale > this.options.minScale || scale < this.options.maxScale) {
                    _element.style.display = 'none';
                    this._elementVisible = false;
                } else {
                    _element.style.display = 'block';
                    this._elementVisible = true;
                };
            } else if (this.options && this.options.minScale > 0) {
                if (scale > this.options.minScale) {
                    _element.style.display = 'none';
                    this._elementVisible = false;
                } else {
                    _element.style.display = 'block';
                    this._elementVisible = true;
                };
            } else if (this.options && this.options.maxScale > 0) {
                if (scale < this.options.maxScale) {
                    _element.style.display = 'none';
                    this._elementVisible = false;
                } else {
                    _element.style.display = 'block';
                    this._elementVisible = true;
                };
            } else {
                _element.style.display = 'block';
                this._elementVisible = true;
            };
        },
        stop: function() {
            clearTimeout(this.timeout);
        },
        animate: function() {
            this.drawAnimation();
            var animateTime = this.options.animateTime || 100;
            this.timeout = setTimeout(this.animate.bind(this), animateTime);
        },
        drawAnimation: function() {
            var ctx = this.ctx;
            var data = this.data;


            if (!data) {
                return;
            }

            ctx.save();
            ctx.globalCompositeOperation = 'destination-out';
            ctx.fillStyle = 'rgba(0, 0, 0, .1)';
            ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
            ctx.restore();

            ctx.save();
            if (this.options.shadowColor) {
                ctx.shadowColor = this.options.shadowColor;
            }

            if (this.options.shadowBlur) {
                ctx.shadowBlur = this.options.shadowBlur;
            }

            if (this.options.globalAlpha) {
                ctx.globalAlpha = this.options.globalAlpha;
            }

            if (this.options.globalCompositeOperation) {
                ctx.globalCompositeOperation = this.options.globalCompositeOperation;
            }

            var options = this.options;

            for (var i = 0; i < data.length; i++) {
                if (data[i].geometry.type === 'Point') {
                    ctx.beginPath();
                    var maxSize = (data[i].symbol && data[i].symbol.size) || data[i].size || this.options.size;
                    var minSize = data[i].minSize || this.options.minSize || 0;
                    if (data[i]._size === undefined) {
                        data[i]._size = minSize;
                    }
                    ctx.arc(data[i].geometry._coordinates[0], data[i].geometry._coordinates[1], data[i]._size, 0, Math.PI * 2, true);
                    ctx.closePath();

                    data[i]._size++;

                    if (data[i]._size > maxSize) {
                        data[i]._size = minSize;
                    };

                    ctx.lineWidth = 1;
                    ctx.strokeStyle = (data[i].symbol && data[i].symbol.strokeStyle) || data[i].strokeStyle || options.strokeStyle || 'yellow';
                    ctx.stroke();
                    var fillStyle = (data[i].symbol && data[i].symbol.fillStyle) || data[i].fillStyle || options.fillStyle;
                    if (fillStyle) {
                        ctx.fillStyle = fillStyle;
                        ctx.fill();
                    }
                } else if (data[i].geometry.type === 'LineString') {
                    ctx.beginPath();
                    var radius = (data[i].symbol && data[i].symbol.radius) || data[i].radius || this.options.radius || 1;
                    if (data[i]._index === undefined) {
                        data[i]._index = 0;
                    };

                    var index = data[i]._index;
                    ctx.arc(data[i].geometry._coordinates[index][0], data[i].geometry._coordinates[index][1], radius, 0, Math.PI * 2, true);
                    ctx.closePath();

                    data[i]._index++;

                    if (data[i]._index >= data[i].geometry._coordinates.length) {
                        data[i]._index = 0;
                    }

                    var strokeStyle = (data[i].symbol && data[i].symbol.strokeStyle) || data[i].strokeStyle || options.strokeStyle;

                    var fillStyle = (data[i].symbol && data[i].symbol.fillStyle) || data[i].fillStyle || options.fillStyle;
                    if (fillStyle) {
                        ctx.fillStyle = fillStyle;
                        ctx.fill();
                    };

                    if (strokeStyle && options.lineWidth) {
                        ctx.lineWidth = (data[i].symbol && data[i].symbol.lineWidth) || data[i].lineWidth || options.lineWidth || 1;
                        ctx.strokeStyle = strokeStyle;
                        ctx.stroke();
                    }
                }
            }
            ctx.restore();
        },

        canvasResolutionScale: function(context) {
            var devicePixelRatio = this.devicePixelRatio;
            context.canvas.width = context.canvas.width * devicePixelRatio;
            context.canvas.height = context.canvas.height * devicePixelRatio;
            context.canvas.style.width = context.canvas.width / devicePixelRatio + 'px';
            context.canvas.style.height = context.canvas.height / devicePixelRatio + 'px';
            context.scale(devicePixelRatio, devicePixelRatio);
        },
        processData: function(data) {
            var self = this;
            var draw = self.options.draw;
            if (draw == 'bubble' || draw == 'intensity' || draw == 'category' || draw == 'choropleth' || draw == 'simple') {

                for (var i = 0; i < data.length; i++) {
                    var item = data[i];

                    if (self.options.draw == 'bubble') {
                        data[i]._size = self.intensity.getSize(item.count);
                    } else {
                        data[i]._size = undefined;
                    }

                    var styleType = '_fillStyle';

                    if (data[i].geometry.type === 'LineString' || self.options.styleType === 'stroke') {
                        styleType = '_strokeStyle';
                    }

                    if (self.options.draw == 'intensity') {
                        data[i][styleType] = self.intensity.getColor(item.count);
                    } else if (self.options.draw == 'category') {
                        data[i][styleType] = self.category.get(item.count);
                    } else if (self.options.draw == 'choropleth') {
                        data[i][styleType] = self.choropleth.get(item.count);
                    }
                }
            }
        },
        removeLayer: function() {
            this.stop();
            this.clear();
            this._watchExtent.remove();
            this._watchExtent = null;
            this.inherited(arguments);
        }
    });
    return animationLayer;
});